package com.simon.seckill.service.impl;

import com.simon.seckill.Entities.Product;
import com.simon.seckill.Exceptions.SeckillExceptions;
import com.simon.seckill.cache.*;
import com.simon.seckill.constant.CommonConstant;
import com.simon.seckill.dao.ProductDao;
import com.simon.seckill.mq.message.SeckillRequestMessage;
import com.simon.seckill.service.ProductService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import wang.moshu.message.Message;
import wang.moshu.message.MessageTrunk;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class ProductServiceImpl implements ProductService {

    @Autowired
    private ProductDao productDao;

    @Autowired
    private SeckillFinishCache seckillFinishCache;

    @Autowired
    private GoodInfoCacheWorker goodInfoCacheWorker;

    @Autowired
    private GoodsBuyCurrentLimiter goodsBuyCurrentLimiter;

    @Autowired
    private SeckillHandingListCache seckillHandingListCache;

    @Autowired
    private SeckillSuccessTokenCache seckillSuccessTokenCache;

    @Autowired
    private MessageTrunk messageTrunk;

    @Override
    public List<Product> getSeckillList() {
        return productDao.selectAllProducts();
    }

    @Override
    public Product getProductById(Integer id) {
        return productDao.getProductById(id);
    }

    @Override
    public String getProductRandomName(Integer id) {
        Product product = goodInfoCacheWorker.get(id, Product.class);
        long now = System.currentTimeMillis();
        // 正在活动中就输出抢购连接
        if (product.getStartTime().getTime()<=now && product.getEndTime().getTime()>now) {
            return product.getRandomName();
        }

        return "";
    }

    @Override
    public void seckill(String phone, String goodRandomName) {
        // 先看抢购是否已经结束
        if (seckillFinishCache.isFinish(goodRandomName)) {
            throw new SeckillExceptions("你已经提交抢购，正在处理");
        }
        // 限流
        goodsBuyCurrentLimiter.doLimit(goodRandomName, "人数太多没挤进去!");
        // 判断是否在处理中
        if (seckillHandingListCache.isInHandleList(phone, goodRandomName)) {
            throw new SeckillExceptions("您已经提交过抢购，请耐心等待...");
        }
        // 请求消息推入处理队列
        Message message = new Message(CommonConstant.MessageType.SECKILL_MESSAGE, new SeckillRequestMessage(phone, goodRandomName));
        messageTrunk.put(message);

        // 加入正在处理列表
        seckillHandingListCache.add2HandleList(phone, goodRandomName);
    }

    @Override
    public Integer order(String phone, Integer goodId, String token) {

        Product productInfo = goodInfoCacheWorker.get(goodId, Product.class);

        // 先检查token的有效性
        if (!seckillSuccessTokenCache.validateToken(phone, productInfo.getRandomName(), token)) {
            throw new SeckillExceptions("token不对，无法下单");
        }

        // 检查库存，没有库存直接结束
        if (!checkStore(productInfo.getRandomName())) {
            throw new SeckillExceptions("库存不足，无法下单");
        }

        // 减库，生成订单
        return reduceStoreAndCreateOrder(phone, goodId);
    }

    /**
     * 减库并生成订单
     * */
    private Integer reduceStoreAndCreateOrder(String phone, Integer goodId) {
        Date orderTime = new Date();
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("goodsId", goodId);
        map.put("mobile", phone);
        map.put("orderTime", orderTime);
        map.put("o_result", -2);
        map.put("o_order_id", -1);
        productDao.createOrder(map);

        Integer result = (Integer) map.get("o_result");

        if (null!=result && 1 == result) {
            return (Integer) map.get("o_order_id");
        }
        throw new SeckillExceptions("下单失败");
    }

    /**
     * 检查库存，true表示有库存，false表示没有库存
     * */
    private boolean checkStore(String goodRandomName) {
        Product product = productDao.getProductByRandomName(goodRandomName);
        if (product == null || product.getStore() <= 0) {
            // 将该产品的秒杀状态设为完成状态
            seckillFinishCache.setFinish(goodRandomName);
            return false;
        }
        return true;
    }
}
